<?php

class site_controller extends base_controller {

    private $__theme = null;

    private $__tmpl = null;

    private $__tmpl_file = null;

    private $__tmpl_main_app_id = null;

    private $__widgets_css = array();

    private $__finish_modifier = array();

    private $__cachecontrol = array(
        'access' => 'public',
        'no-cache' => '',
        'no-store' => '',
        'max-age' => 'max-age=1'
    );

    public $transaction_start = false;

    public $contentType = 'text/html;charset=utf-8';

    public $enable_strip_whitespace = true;

    public $is_splash = false;

    function __construct(&$app) {
        parent::__construct($app);
        if (@constant('WITHOUT_STRIP_HTML')) {
            $this->enable_strip_whitespace = false;
        }
        $this->app = $app;
        $this->_request = kernel::single('base_component_request');
        $this->_response = kernel::single('base_component_response');
        
        foreach (kernel::serviceList('site_controller_construct') as $service) {
            $service->prepare($this);
        } // 构造时加载
          
        // finish modify controler-action html
        foreach (kernel::serviceList(sprintf('site_controller_content.%s.%s.%s', $this->_request->get_app_name(), $this->_request->get_ctl_name(), $this->_request->get_act_name())) as $class_name => $service) {
            if ($service instanceof site_interface_controller_content) {
                if (method_exists($service, 'modify')) {
                    $this->__finish_modifier[$class_name] = $service;
                }
                if (method_exists($service, 'boot')) {
                    $service->boot($this);
                }
            }
        }
    }
 // End Function
    public function get_browser() {
        $agent = $_SERVER['HTTP_USER_AGENT'];
        $browser = 'others';
        $browser_ver = '-';
        
        if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'Safari';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) {
            $browser = 'IE';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) {
            $browser = 'Opera';
            $browser_ver = $regs[1];
        }
        if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) {
            $browser = 'FireFox';
            $browser_ver = $regs[1];
        }
        return array(
            'name' => $browser,
            'ver' => floor($browser_ver)
        );
    }

    public function append_widgets_css($css) {
        $this->__widgets_css = array_merge($this->__widgets_css, $css);
    }
 // End Function
    public function extract_widgets_css(&$body) {
        preg_match_all('/<\s*style.*?>(.*?)<\s*\/\s*style\s*>/is', $body, $matchs);
        if (isset($matchs[0][0]) && ! empty($matchs[0][0])) {
            foreach ($matchs[0] as $matchcontent) {
                $body = str_replace($matchcontent, '', $body);
            }
            $this->append_widgets_css($matchs[1]);
        }
    }
 // End Function
    public function create_widgets_key_prefix($values, $varys) {
        $ret['__PREFIX__'] = 'WIDGETS_CACHE_KEY';
        if ($varys[0] == '*') {
            $ret['*'] = $values;
        } else {
            foreach ($varys as $vary) {
                $ret[$vary] = $values[$vary];
            }
        }
        ksort($ret);
        return serialize($ret);
    }
 // End Function
    final public function gen_url($params = array()) {
        return app::get('site')->router()->gen_url($params);
    }
 // End Function
    final public function set_tmpl($tmpl) {
        $this->__tmpl = $tmpl;
    }
 // End Function
    final public function get_tmpl() {
        return $this->__tmpl;
    }
 // End Function
    final public function set_tmpl_file($tmpl_file) {
        $this->__tmpl_file = $tmpl_file;
    }
 // End Function
    final public function get_tmpl_file() {
        return $this->__tmpl_file;
    }
 // End Function
    final public function set_theme($theme) {
        $this->__theme = $theme;
    }
 // End Function
    final public function get_theme() {
        return $this->__theme;
    }
 // End Function
    protected function _fetch_tmpl_compile_require($tmpl_file, $is_preview = false) {
        $html = $this->fetch_tmpl($tmpl_file, $is_preview);
        if ($tmpl_file == 'block/header.html') {
            $this->_change_style($html);
        } // todo: 如果是header文件，考虑换肤设置~~~~~~~~ 今后可能会有用户设置换肤问题
        return $html;
    }
 // End Function
    protected function _change_style(&$html) {
        $style = kernel::single('site_theme_base')->get_theme_style($this->get_theme());
        if (! empty($style['value'])) {
            $style_css = kernel::single('site_theme_file')->get_style_css($this->get_theme(), $style['value']);
            $html .= sprintf('<link href="%s" rel="stylesheet">', $style_css);
        }
    }
 // End Function
    private function fix_theme_media($code) {
        $from = array(
            '/((?:background|src|href)\s*=\s*["|\'])(?:\.\/|\.\.\/)?(images\/.*?["|\'])/is',
            '/((?:background|background-image):\s*?url\()(?:\.\/|\.\.\/)?(images\/)/is',
            '/<!--[^<|>|{|\n]*?-->/'
        );
        
        $theme_url = kernel::get_themes_host_url();
        
        $to = array(
            '\1<?php echo \$theme_url, "/", \$this->get_theme(), "/";?>\2',
            '\1<?php echo \$theme_url, "/", \$this->get_theme(), "/";?>\2',
            ''
        );
        return preg_replace($from, $to, $code);
    }
 // End Function
    final public function set_tmpl_main_app_id($app_id) {
        $this->__tmpl_main_app_id = $app_id;
    }
 // End Function
    final public function get_tmpl_main_app_id() {
        return $this->__tmpl_main_app_id;
    }
 // End Function
    final public function display_tmpl($tmpl, $fetch = false, $is_preview = false) {
        array_unshift($this->_files, $this->get_theme() . '/' . $tmpl);
        $this->_vars = $this->pagedata;
        $tmpl_file = realpath(THEME_DIR . '/' . $this->get_theme() . '/' . $tmpl);
        $this->tmpl_cachekey('__theme_app_id', ($this->get_tmpl_main_app_id() ? $this->get_tmpl_main_app_id() : $this->app->app_id));
        $this->tmpl_cachekey('__theme_main_page', $this->pagedata['_MAIN_']);
        $compile_id = $this->compile_id($this->get_theme() . "/" . $tmpl);
        $last_modified = filemtime($tmpl_file);
        // if($this->force_compile || base_kvstore::instance('cache/theme')->fetch($compile_id, $compile_code, filemtime($tmpl_file))===false){
        
        if (! $is_preview) {
            if ($this->force_compile || ! cachemgr::get($compile_id . $last_modified, $compile_code)) {
                cachemgr::co_start();
                
                $tmpl_content = kernel::single('site_theme_file')->get_tmpl_content($this->get_theme(), $tmpl);
                $compile_code = $this->_compiler()->compile($tmpl_content);
                
                if ($compile_code !== false) {
                    $compile_code = $this->fix_theme_media($compile_code);
                    // base_kvstore::instance('cache/theme')->store($compile_id, $compile_code);
                }
                cachemgr::set($compile_id . $last_modified, $compile_code, cachemgr::co_end());
            }
        } else {
            $this->_compiler()->is_preview = $is_preview;
            
            $tmpl_content = kernel::single('site_theme_file')->get_tmpl_content($this->get_theme(), $tmpl);
            $compile_code = $this->_compiler()->compile($tmpl_content);
            
            if ($compile_code !== false) {
                $compile_code = $this->fix_theme_media($compile_code);
            }
        }
        
        kernel::single('site_theme_base')->get_theme_cache_version($this->get_theme());
        
        $theme_url = kernel::get_themes_host_url();
        ob_start();
        eval('?>' . $compile_code);
        $content = ob_get_contents();
        ob_end_clean();
        array_shift($this->_files);
        
        $this->pre_display($content);
        
        if ($fetch === true) {
            return $content;
        } else {
            echo $content;
        }
    }
 // End Function
    final public function fetch_tmpl($tmpl, $is_preview = false) {
        return $this->display_tmpl($tmpl, true, $is_preview);
    }
 // End Function
    final public function page($view, $no_theme = false, $app_id = null) {
        $params = $this->_request->get_params(true);
        $current_theme = ($params['theme']) ? $params['theme'] : kernel::single('site_theme_base')->get_default();
        $is_preview = (isset($_COOKIE['site']['preview']) && $_COOKIE['site']['preview'] == 'true') ? true : false;
        $views = kernel::single('site_theme_base')->get_theme_views($current_theme);
        $views_app_id = is_null($app_id) ? $this->app->app_id : $app_id;
        if (is_array($views[$views_app_id]) && array_key_exists($view, $views[$views_app_id])) {
            $view = 'theme:' . $views[$views_app_id][$view];
        } else {
            $service = kernel::service(sprintf('site_controller_display.%s.%s.%s', $this->_request->get_app_name(), $this->_request->get_ctl_name(), $this->_request->get_act_name()));
            if (is_object($service)) {
                if (method_exists($service, 'get_view'))
                    $view = $service->get_view();
                if (method_exists($service, 'get_app_id'))
                    $app_id = $service->get_app_id();
                if (method_exists($service, 'get_no_theme'))
                    $no_theme = $service->get_no_theme();
            }
        }
        
        $global_prepare = kernel::servicelist('site_controller_prepare');
        $single_prepare = kernel::servicelist(sprintf('site_controller_prepare.%s.%s.%s', $this->_request->get_app_name(), $this->_request->get_ctl_name(), $this->_request->get_act_name()));
        foreach ($global_prepare as $prepare) {
            $prepare->modify($this);
        }
        foreach ($single_prepare as $prepare) {
            $prepare->modify($this);
        }
        if ($no_theme == false && $current_theme) {
            $this->set_theme($current_theme);
            $this->pagedata['_MAIN_'] = $view; // 强制替换
            $this->pagedata['_THEME_'] = kernel::get_themes_host_url() . "/" . $this->get_theme(); // 模版地址
            $tmpl_file = $this->get_tmpl_file(); // 指定模板
            $tmplObj = kernel::single('site_theme_tmpl');
            if (! $tmpl_file || ! $tmplObj->tmpl_file_exists($tmpl_file, $current_theme)) {
                $tmpl = ($this->get_tmpl()) ? $this->get_tmpl() : 'defalut';
                $tmpl = $tmplObj->get_default($tmpl, $current_theme);
                $tmpl_file = ($tmpl) ? $tmpl : (($tmpl_default = $tmplObj->get_default('default', $current_theme)) ? $tmpl_default : 'default.html');
            } // 如果有模版，检测当前theme下是否有此模板
            $this->set_tmpl_main_app_id($app_id);
            $html = $this->fetch_tmpl($tmpl_file, $is_preview);
        } else {
            $html = $this->fetch($view, $app_id, $is_preview);
        }
        
        // finish html modify
        foreach ($this->__finish_modifier as $modifier) {
            $modifier->modify($html, $this);
        }
        
        // modify html services
        $services = kernel::servicelist('site_controller_content');
        foreach ($services as $service) {
            if ($service instanceof site_interface_controller_content) {
                $service->modify($html, $this);
            }
        }
        
        // append widgets css add by edwin.lzh@gmail.com 2010/6/11
        // $html = str_replace('<%site_widgets_css%>', implode("", array_unique($this->__widgets_css)), $html);
        $this->extract_widgets_css($html);
        $html = str_replace('<%site_widgets_css%>', app::get('site')->base_url(1) . 'widgetsproinstance-get_css-' . $current_theme . '-' . base64_encode($tmpl_file) . ((app::get('site')->getConf('base.enable_site_uri_expanded') == 'true') ? '.' . app::get('site')->getConf('base.site_uri_expanded_name') : ''), $html);
        
        // filter html special
        if ($this->enable_strip_whitespace) {
            $this->strip_whitespace($html);
        }
        if (! $this->_response->get_header('Content-type', $header)) {
            $this->_response->set_header('Content-type', $this->contentType, true);
        } // 如果没有定义Content-type，默认加text/html;charset=utf-8
        
        if (! $this->_response->get_header('Cache-Control', $header)) {
            $$cache_control = array();
            foreach ($this->__cachecontrol as $val) {
                $val = trim($val);
                if (empty($val))
                    continue;
                $cache_control[] = $val;
            }
            $this->_response->set_header('Cache-Control', join(',', $cache_control), true);
        } // 如果没有定义Content-Control，使用系统配置
        
        $this->_response->set_body($html);
    }

    final public function strip_whitespace(&$html) {
        $html = preg_replace("/(<[\s\n\r\t]{0,}script[^>]{0,}>[\s\n\r\t]{0,})<!--(.*?)[\/\/]{0,2}-->([\s\n\r\t]{0,}<[\s\n\r\t]{0,}\/[\s\n\r\t]{0,}script[\s\n\r\t]{0,}>)/is", "\\1\\2\\3", $html);
        $html = preg_replace("/(<[\s\n\r\t]{0,}style[^>]{0,}>[\s\n\r\t]{0,})<!--(.*?)[\/\/]{0,2}-->([\s\n\r\t]{0,}<[\s\n\r\t]{0,}\/[\s\n\r\t]{0,}style[\s\n\r\t]{0,}>)/is", "\\1\\2\\3", $html);
        // replace <!-- -->
        $html = preg_replace("|<!-- /\*(.*)\*/ -->|isU", "", $html);
        // replace all \n\r to null
        $html = preg_replace("![\n\r]{2,}!is", "\n", $html);
        // replace space to null
        $html = preg_replace("!\n[\s\t]{1,}!is", "\n", $html);
        // replace space to null
        $html = preg_replace("![\x20\t]{1,}!is", " ", $html);
    }
 // End Function
    final public function redirect($url, $js_jump = false) {
        if (is_array($url)) {
            $url = $this->gen_url($url);
        }
        if ($js_jump) {
            echo "<header><meta http-equiv=\"refresh\" content=\"0; url={$url}\"></header>";
            exit();
        } else {
            $this->_response->set_redirect($url)->send_headers();
        }
        exit();
    }
 // End Function
    function begin($url = null, $errAction = null, $shutHandle = null) {
        $this->_action_url = $url;
        $this->_errAction = $errAction;
        $this->_shutHandle = $shutHandle ? $shutHandle : (E_USER_ERROR | E_ERROR | E_USER_WARNING);
        set_error_handler(array(
            &$this,
            '_errorHandler'
        ), $this->_shutHandle);
        if ($this->transaction_start)
            trigger_error('The transaction has been started', E_USER_ERROR);
        $this->transaction_start = true;
    }

    function end($result = true, $message = null, $url = null, $show_notice = false, $ajax = false) {
        if (! $this->transaction_start)
            trigger_error('The transaction has not started yet', E_USER_ERROR);
        $this->transaction_start = false;
        restore_error_handler();
        if (is_null($url)) { // 如果是错误则在当前页面返回错误信息
            $url = $this->_action_url;
        }
        $this->splash($result ? 'success' : 'failed', $url, $result ? $message : ($message ? $message : app::get('site')->_('操作失败')), $ajax);
    }

    function end_only() {
        if (! $this->transaction_start)
            trigger_error('The transaction has not started yet', E_USER_ERROR);
        $this->transaction_start = false;
        restore_error_handler();
    }

    public function splash($status = 'success', $url = '', $msg = null, $ajax = false, $data = null) {
        $status = ($status == 'failed') ? 'error' : $status;
        $url = is_array($url) ? $this->gen_url($url) : $url;
        
        $params = $this->_request->get_params(true);
        // 如果需要返回则ajax
        if (($params['response_json'] == 'true' || $ajax == true)) {
            header("Cache-Control:no-store, no-cache, must-revalidate"); // HTTP/1.1
            header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // 强制查询etag
            header('Progma: no-cache');
            header('Content-Type:text/jcmd; charset=utf-8');
            $default = array(
                $status => $msg,
                'redirect' => $url
            );
            if ($data) {
                $default['data'] = $data;
            }
            $json = json_encode($default);
            echo $json;
            exit();
        }
        
        if ($url && ! $msg) { // 如果有url地址但是没有信息输出则直接跳转
            $this->redirect($url);
            exit();
        }
        $this->set_tmpl('splash');
        $this->pagedata['msg'] = $msg;
        $this->_response->set_header('Cache-Control', 'no-store, no-cache')
            ->set_header('Content-type', $this->contentType)
            ->send_headers();
        $this->set_tmpl('splash');
        $this->page('splash/error.html', false, 'site');
        echo join("\n", $this->_response->get_bodys());
        exit();
    }

    public function set_max_age($time) {
        $this->__cachecontrol['max-age'] = 'max-age=' . (($time >= 0) ? intval($time) : 1);
    }
 // End Function
    public function set_no_cache($status = true) {
        if ($status) {
            $this->__cachecontrol['no-cache'] = 'no-cache';
            $this->set_max_age(0);
        } else {
            $this->__cachecontrol['no-cache'] = '';
        }
    }
 // End Function
    public function set_no_store($status = true) {
        if ($status) {
            $this->__cachecontrol['no-store'] = 'no-store';
            $this->set_max_age(0);
        } else {
            $this->__cachecontrol['no-store'] = '';
        }
    }
 // End Function
    public function set_cache_access($access = 'public') {
        $this->__cachecontrol['access'] = ($access == 'public') ? 'public' : ((empty($access)) ? '' : 'private');
    } // End Function
}//End Class
